package com.danger.dy.blogger.chatgpt;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletResponse;

import com.danger.dy.common.lang.utils.JsonUtils;
import com.danger.dy.common.lang.utils.Lang;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * .
 */
@Slf4j
@RestController
@RequestMapping("/api/chat")
public class ChatAIController {

//    public static void main(String[] args) throws Exception {
//        OkHttpClient client = new OkHttpClient.Builder()
//                .readTimeout(0, TimeUnit.SECONDS)
//                .build();
//
//        Request request = new Request.Builder()
//                .url("http://localhost:8080/api/chat/download")
//                .build();
//
//        try (Response response = client.newCall(request).execute()) {
//            if (!response.isSuccessful()) {
//                throw new IOException("Unexpected code " + response);
//            }
//
//            okhttp3.ResponseBody responseBody = response.body();
//            BufferedSource source = responseBody.source();
//
//            while (!source.exhausted()) {
//                String chunk = source.readUtf8Line();
//                // 处理每个数据块
//                System.out.println(chunk);
//            }
//        }
//
//    }

//    @GetMapping("/download")
//    @ResponseBody
//    @Async
//    public CompletableFuture<ResponseEntity<StreamingResponseBody>> download() throws InterruptedException {
//        HttpHeaders headers = new HttpHeaders();
//        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
//        headers.setContentDisposition(ContentDisposition.attachment().filename("example.txt").build());
//        headers.add("Transfer-Encoding", "chunked");
//        StreamingResponseBody responseBody = new StreamingResponseBody(){
//            @Override
//            public void writeTo(OutputStream outputStream) throws IOException {
//                outputStream.write("Hello".getBytes());
//                log.info("wwwwwwwwwwww");
//                try {
//                    Thread.sleep(5000); // 模拟耗时操作
//                } catch (InterruptedException e) {
//                    throw new RuntimeException(e);
//                }
//                outputStream.write("World".getBytes());
//                outputStream.flush();
//                log.info("yyyyyyyyyyyy");
//            }
//        };
//
//        log.info("uuuuuuuuuuuuu");
//        return CompletableFuture.completedFuture(ResponseEntity.ok()
//                .headers(headers)
//                .body(responseBody));
//    }

    @PostMapping("/chat-process")
//    @ResponseBody
    public void chatProcess(HttpServletResponse response) throws IOException {
        response.setContentType("application/octet-stream");
        response.setHeader("Transfer-Encoding", "chunked");
        // chatgpt总是会返回至少两行，首行text是空，末行finish_reason是stop，中间的行才是承载结果，末行其实并没有delta

        String id = "chatcmpl-75yhuN2rbFXmSBwMfNFPorrvokJ3I";
        String parentMessageId = "c1fcce17-4525-43f3-a0be-ab93b5da0863";
        String text = "Redis是一种高性能的内存数据结构存储系统，它是一个开源、基于内存的键值存储系统，支持多种数据类型。";

        // 返回首行
        {
            AIResponse ret = new AIResponse();
            ret.setRole("assistant");
            ret.setId(id);
            ret.setParentMessageId(parentMessageId);
            ret.setText("");
            AIAnswer detail = new AIAnswer();
            ret.setDetail(detail);
            detail.setId(id);
            detail.setObject("chat.completion.chunk");
            detail.setCreated(System.currentTimeMillis());
            detail.setModel("gpt-3.5-turbo-0301");
            detail.setChoices(new ArrayList<>());
            Choice choice = new Choice();
            detail.getChoices().add(choice);
            Map delta = new HashMap();
            delta.put("role", "assistant");
            choice.setDelta(delta);
            choice.setIndex(0);
            choice.setFinish_reason(null);
            response.getOutputStream().write((JsonUtils.toJson(ret) + "\n").getBytes(StandardCharsets.UTF_8));
//            response.getOutputStream().flush();
//            Lang.sleep(100);
        }

        // 返回中间行
        String buf = "";
        for (int i = 0; i < text.length(); i++) {
            String t = text.charAt(i) + "";
            buf += t;
            AIResponse ret = new AIResponse();
            ret.setRole("assistant");
            ret.setId(id);
            ret.setParentMessageId(parentMessageId);
            ret.setText(buf);
            ret.setDelta(t);

            AIAnswer detail = new AIAnswer();
            ret.setDetail(detail);
            detail.setId(id);
            detail.setObject("chat.completion.chunk");
            detail.setCreated(System.currentTimeMillis());
            detail.setModel("gpt-3.5-turbo-0301");
            detail.setChoices(new ArrayList<>());
            Choice choice = new Choice();
            detail.getChoices().add(choice);
            Map delta = new HashMap();
            delta.put("content", t);
            choice.setDelta(delta);
            choice.setIndex(0);
            choice.setFinish_reason(null);
            response.getOutputStream().write((JsonUtils.toJson(ret) + "\n").getBytes(StandardCharsets.UTF_8));
            response.getOutputStream().flush();
            // 这里flush页没法立即返回？前端还是没法出现打字机效果，好像spring总是要等计算完content-length
//            Lang.sleep(200);
        }

        // 返回末行
        {
            AIResponse ret = new AIResponse();
            ret.setRole("assistant");
            ret.setId(id);
            ret.setParentMessageId(parentMessageId);
            ret.setText(text);
            AIAnswer detail = new AIAnswer();
            ret.setDetail(detail);
            detail.setId(id);
            detail.setObject("chat.completion.chunk");
            detail.setCreated(System.currentTimeMillis());
            detail.setModel("gpt-3.5-turbo-0301");
            detail.setChoices(new ArrayList<>());
            Choice choice = new Choice();
            detail.getChoices().add(choice);
            Map delta = new HashMap();
            choice.setDelta(delta);
            choice.setIndex(0);
            choice.setFinish_reason("stop");
            response.getOutputStream().write((JsonUtils.toJson(ret) + "\n").getBytes(StandardCharsets.UTF_8));
            response.getOutputStream().flush();
            Lang.sleep(100);
        }


//        String s1 = "{\"role\":\"assistant\",\"id\":\"chatcmpl-75yhuN2rbFXmSBwMfNFPorrvokJ3I\"," +
//                "\"parentMessageId\":\"c1fcce17-4525-43f3-a0be-ab93b5da0863\",\"text\":\"\",\"detail\":{\"id\":\"chatcmpl-75yhuN2rbFXmSBwMfNFPorrvokJ3I\",\"object\":\"chat.completion.chunk\",\"created\":1681659354,\"model\":\"gpt-3.5-turbo-0301\",\"choices\":[{\"delta\":{\"role\":\"assistant\"},\"index\":0,\"finish_reason\":null}]}}\n";
//        String s2= "{\"role\":\"assistant\",\"id\":\"chatcmpl-75yhuN2rbFXmSBwMfNFPorrvokJ3I\"," +
//            "\"parentMessageId\":\"c1fcce17-4525-43f3-a0be-ab93b5da0863\",\"text\":\"Redis是一种高性能的内存数据结构存储系统，它是一个开源、基于内存的键值存储系统，支持多种数据类型。由于其高效性和灵活性，Redis的应用场景非常广泛，以下是一些常见的使用场景：\\n\\n1. 缓存：Redis最常见的使用场景就是缓存服务，将热点数据存储在Redis中，以加快访问速度。例如，将数据库查询结果缓存在Redis中，下次查询时直接从Redis中获取，避免了重复查询数据库。\\n\\n2. 计数器和排行榜：Redis可以用来实现计数器和排行榜功能。例如，记录文章的浏览量或用户的点赞数，并根据这些数据对文章或用户进行排名。\\n\\n3. 消息队列：Redis支持发布/订阅模式，可以作为消息队列使用。例如，将任务放入Redis队列中，由消费者程序获取并执行任务。\\n\\n4. 分布式锁：Redis提供了setnx命令，可以实现分布式锁。例如，在分布式环境下，确保同一时间只有一个节点对某个资源进行操作。\\n\\n5. 地理位置：Redis支持地理位置相关的操作，例如存储经纬度信息，计算两个地点之间的距离等。\\n\\n6. 实时数据分析：Redis可以存储大量的实时数据，并通过各种数据结构和操作方式，对数据进行分析和处理。\\n\\n总之，Redis是一款非常灵活的数据存储系统，适用于各种场景。\",\"detail\":{\"id\":\"chatcmpl-75yhuN2rbFXmSBwMfNFPorrvokJ3I\",\"object\":\"chat.completion.chunk\",\"created\":1681659354,\"model\":\"gpt-3.5-turbo-0301\",\"choices\":[{\"delta\":{},\"index\":0,\"finish_reason\":\"stop\"}]}}";
//        response.getOutputStream().write(s1.getBytes(StandardCharsets.UTF_8));
//        response.getOutputStream().flush();
//        Lang.sleep(1000);
//        response.getOutputStream().write(s2.getBytes(StandardCharsets.UTF_8));

    }
}
